﻿using System;
using Patterns.Interfaces;

namespace Patterns.DataProcessing.Aggregation
{
    public class GenericAgregator<TAccumulate, TTerminate> : IAggregate<TAccumulate, TTerminate>
    {
        #region fields
        private readonly TAccumulate _initialValue;
        private TAccumulate _buffer;
        private readonly Func<TAccumulate, TAccumulate, TAccumulate> _accumulateFunc;
        private readonly Func<TAccumulate, TAccumulate, TAccumulate> _dissipateFunc;
        #endregion

        #region Constructor
        public GenericAgregator(
            TAccumulate initialValue, 
            Func<TAccumulate, TAccumulate, TAccumulate> accumulateFunc,
            Func<TAccumulate, TAccumulate, TAccumulate> dissipateFunc)
        {
            _initialValue = initialValue;
            _accumulateFunc = accumulateFunc;
            _dissipateFunc = dissipateFunc;
        }
        #endregion

        #region Implementation of IAggregator

        public void Initialize() { _buffer = _initialValue; }

        public void Accumulate(object accumulate) { Accumulate((TAccumulate)accumulate); }

        public void Dissipate(object dissipate) { Dissipate((TAccumulate) dissipate); }

        public void Dissipate(TAccumulate dissipate) { _buffer = _dissipateFunc(_buffer, dissipate); }

        public TTerminate Terminate() { return (TTerminate)((object)_buffer); }

        public void Accumulate(TAccumulate accumulate) { _buffer = _accumulateFunc(_buffer, accumulate); }

        object IAggregate.Terminate() { return Terminate(); }
        #endregion
    }
}
